package com.nova.bluetooth.xunFeiSDK.optionalFunction;

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ScrollView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.iflytek.aiui.AIUIAgent;
import com.iflytek.aiui.AIUIConstant;
import com.iflytek.aiui.AIUIListener;
import com.nova.bluetooth.R;
import com.nova.bluetooth.xunFeiSDK.engine.AiuiEngine;
import com.nova.bluetooth.xunFeiSDK.engine.EngineConstants;
import com.nova.bluetooth.xunFeiSDK.utils.CopyAssetsUtils;
import com.nova.bluetooth.xunFeiSDK.utils.ErrorCode;
import com.nova.bluetooth.xunFeiSDK.utils.StreamingAsrUtil;


import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * 1.读取assets音频文件后识别
 * 2.音频路径：filePath
 * 3.默认单麦算法，数据格式为1mic+1ref。其他格式音频需要匹配算法，替换assets下的libvtn.so
 */
public class ReadFileTest_Asr extends AppCompatActivity implements View.OnClickListener {
    private static final String TAG = ReadFileTest_Asr.class.getSimpleName();
    public ExecutorService executor;   //单线程执行器，保证一个一个文件识别
    Handler handler = new Handler();
    String filePath = "audio/16k16bit-1ch1mic-weather.pcm"; //测试音频
    Button btnAsrResult; //asr结果
    private TextView mResText;
    private ScrollView mScrollView;
    // AIUI
    private AIUIAgent mAIUIAgent;
    boolean isFirstFrame = true; //判断是不是wav的第一帧，如果是要去掉前面44字节


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_asr);
        initLayout();
        // 资源拷贝
        CopyAssetsUtils.portingFile(this);
    }

    private void initLayout() {
        findViewById(R.id.init_sdk).setOnClickListener(this);
        findViewById(R.id.btnStartRecord).setOnClickListener(this);
        findViewById(R.id.btnSave).setVisibility(View.INVISIBLE);
        ((TextView) findViewById(R.id.myTitle)).setText("读音频识别测试");
        mScrollView = findViewById(R.id.scrollView);
        mResText = findViewById(R.id.res_text);
        btnAsrResult = findViewById(R.id.btnStopRecord);
        btnAsrResult.setText("");
        Button btnStartRecord = findViewById(R.id.btnStartRecord);
        btnStartRecord.setText("读音频测试识别");
        mResText.append("sdk默认使用单麦算法，其他格式音频请替换assets下的libvtn.so");
        mResText.append("-------\n");
    }

    @Override
    public void onClick(View view) {
        int id = view.getId();
        if (id == R.id.init_sdk) {
            initSDK();
        } else if (id == R.id.btnStartRecord) {
            writeAudioTest();
        }
    }

    /**
     * AIUI 回调信息处理
     */
    private AIUIListener mAIUIListener = event -> {
        switch (event.eventType) {
            case AIUIConstant.EVENT_RESULT:
                //处理识别结果
                if (event.info.contains("\"sub\":\"iat")) {
                    JSONObject cntJson = JSON.parseObject(new String(event.data.getByteArray("0"), StandardCharsets.UTF_8));
                    JSONObject text = cntJson.getJSONObject("text");
                    //识别结果
                    String asrResult = StreamingAsrUtil.processIATResult(text);
                    btnAsrResult.setText(asrResult);
                    //最后一次asr返回(ls==true)
                    if (text.getBoolean("ls")) {
                        setText(asrResult);        //打印到屏幕
                        Log.i(TAG, "识别结果：" + asrResult);
                    }
                }
                break;
            case AIUIConstant.EVENT_VAD:
                if (AIUIConstant.VAD_BOS == event.arg1) {
                    Log.i(TAG, "vad_bos,开始说话");
                } else if (AIUIConstant.VAD_BOS_TIMEOUT == event.arg1) {
                    Log.i(TAG, "vad timeout,不说话,前端点超时");
                } else if (AIUIConstant.VAD_EOS == event.arg1) {
                    Log.i(TAG, "vad eos,结束说话");
                } else if (AIUIConstant.VAD_VOL == event.arg1) {
//                    Log.i(TAG, "vad vol,说话音量:" + event.arg2);
                }
                break;

            case AIUIConstant.EVENT_ERROR:
                setText("错误码: " + event.arg1);
                setText("错误信息:" + event.info);
                setText("解决方案:" + ErrorCode.getError(event.arg1) + "\n  错误解决详情参考：https://www.yuque.com/iflyaiui/zzoolv/igbuol");
                break;
            case AIUIConstant.EVENT_STATE:    // 状态事件
                EngineConstants.mAIUIState = event.arg1;
                break;

            default:
                break;
        }
    };

    private void initSDK() {
        //状态初始化
        EngineConstants.isRecording = false;
        EngineConstants.isWriting = false;
        //TODO 测试时保存音频分析，量产需关闭保存音频
        EngineConstants.saveAudio=true;
        //获取设备sn,用户可自定义sn，比如型号+mac
        //注意事项1: sn每台设备需要唯一！！！！cae的sn和AIUI的sn要一致
        //注意事项2: 获取的值要保持稳定，否则会重复授权，浪费授权量
        EngineConstants.serialNumber = "iflytek-test";
        // 初始化AIUI(识别+语义+合成）
        mAIUIAgent = AiuiEngine.getInstance(mAIUIListener);
        if (mAIUIAgent != null) {
            setText("AIUI初始化成功");
        } else {
            setText("AIUI初始化失败");
        }
    }


    //根据scrollView 和子view去测量滑动的位置
    private void scrollToBottom(final ScrollView scrollView, final View view) {
        handler.post(() -> {
            if (scrollView == null || view == null) {
                return;
            }
            // offset偏移量。是指当textview中内容超出 scrollview的高度，超出部分就是偏移量
            int offset = view.getMeasuredHeight()
                    - scrollView.getMeasuredHeight();
            if (offset < 0) {
                offset = 0;
            }
            //scrollview开始滚动
            scrollView.scrollTo(0, offset);
        });
    }

    private void setText(final String str) {
        if (Looper.getMainLooper() == Looper.myLooper()) {
            mResText.append(str + " \n");
            scrollToBottom(mScrollView, mResText);
        } else {
            runOnUiThread(() -> {
                mResText.append(str + " \n");
                scrollToBottom(mScrollView, mResText);
            });
        }
    }

    /**
     * 读取外部音频写入 CAE SDK
     */
    private void writeAudioTest() {
        if (EngineConstants.isRecording || EngineConstants.isWriting) {
            return;
        }
        EngineConstants.isWriting = true;
        executor = Executors.newSingleThreadExecutor();
        byte[] audio = new byte[1280];//1声道1ms有32bytes数据。一次只送部分数据去识别
        for (int i = 0; i < 1; i++) {
            Thread speedTestThread = new Thread(() -> {
                // 写入音频
                InputStream in;
                try {
                    in = getResources().getAssets().open(filePath);
                    AiuiEngine.MSG_wakeup(EngineConstants.WAKEUPTYPE_VOICE);
                    isFirstFrame = true;
                    // 流式读取文件写入aiui
                    while (in.read(audio) != -1) {
                        if (filePath.endsWith("wav") && isFirstFrame) {
                            isFirstFrame = false;
                            //去掉wav的44字节文件头
                            byte[] filterWavHeaderData = new byte[audio.length - 44];
                            System.arraycopy(audio, 44, filterWavHeaderData, 0, filterWavHeaderData.length);
                            //写入音频给aiui去识别
                            AiuiEngine.MSG_writeAudio(filterWavHeaderData);
                        } else {
                            AiuiEngine.MSG_writeAudio(audio);
                        }
                        Thread.sleep(40);
                    }
                    Log.i(TAG, "音频读取完成");
                    in.close();
                    EngineConstants.isWriting = false;
                } catch (Exception e) {
                    e.printStackTrace();
                    EngineConstants.isWriting = false;
                }
            });
            executor.execute(speedTestThread);//执行测试
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mAIUIListener != null) {
            mAIUIListener = null;
        }
        AiuiEngine.destroy();//结束时一定要调用destroy()，否则aiui的navite方法状态异常
    }
}